#include "ET++.ph"
#include "Converter.h"

#include "Class.h"
#include "Data.h"
#include "Bitmap.h"
#include "DevBitmap.h"
#include "String.h"
#include "TypeMatcher.h"
#include "ET_stdio.h"

static const Symbol cDocTypeX11Bitmap("X11BITMAP");
static TypeMatcher matcher(cDocTypeX11Bitmap, 0, "#define", TRUE);

//---- XIconConverter ----------------------------------------------------------

class XIconConverter : public Converter {
public:
	MetaDef(XIconConverter);
	XIconConverter()
		{ }
	const char *AsString()
		{ return "X Icon"; }
	Object *Convert(Data *data, Class *want);
	bool CanConvert(Data *data, Class *want)
		{ return data->Type() == cDocTypeX11Bitmap && want == Meta(Bitmap); }
};

NewMetaImpl0(XIconConverter,Converter);

Object *XIconConverter::Convert(Data *data, Class*)
{
	static byte *swapmap= 0;

	FILE *fp;
	int tmp, width= 0, height= 0, depth= 1, bitsperitem= 16;
	int b, x= 0, y= 0, bytesperitem, itemsperline;
	u_long mask, m, d;
	char buf[200], token[100], c;
	Bitmap *BM;
	DevBitmap *dbm;

	if ((fp= fopen((char*) data->Name(), "r")) == 0)
		return 0;

	while (fscanf(fp, "%s", buf) == 1) {
		if (strcmp(buf, "#define") == 0) {
			if (fscanf(fp, "%s %d", token, &tmp) == 2) {
				int l= strlen(token);
				if (strcmp(&token[l-6], "_width") == 0) {
					width= tmp;
					continue;
				}
				if (strcmp(&token[l-7], "_height") == 0) {
					height= tmp;
					continue;
				}
			}
		}
		if (strcmp(buf, "char") == 0) {
			bitsperitem= sizeof(char) * 8;
			continue;
		}
		if (strcmp(buf, "short") == 0) {
			bitsperitem= sizeof(short) * 8;
			continue;
		}
		if (strcmp(buf, "int") == 0) {
			bitsperitem= sizeof(int) * 8;
			continue;
		}
		if (strcmp(buf, "{") == 0)
			break;
	}

	if (width <= 0 || height <= 0)
		return 0;
		
	BM= new Bitmap(Point(width, height), depth);
	dbm= BM->GetDevBitmap();
	itemsperline= (width-1) / bitsperitem + 1;
	bytesperitem= bitsperitem / 8;
	mask= 0xff << (bytesperitem-1)*8;

	if (swapmap == 0) {
		int rb;
		swapmap= new byte[256];
		for (int i= 0; i < 256; i++) {
			rb= 0;
			if (i & 0x01)
				rb|= 0x80;
			if (i & 0x02)
				rb|= 0x40;
			if (i & 0x04)
				rb|= 0x20;
			if (i & 0x08)
				rb|= 0x10;
			if (i & 0x10)
				rb|= 0x08;
			if (i & 0x20)
				rb|= 0x04;
			if (i & 0x40)
				rb|= 0x02;
			if (i & 0x80)
				rb|= 0x01;
			swapmap[i]= rb;
		}
	}

	BitmapInfo bi(Point(width, height), depth, 1);

	byte *bbuf= new byte[bi.rowlen],
		*bp= bbuf;
		
	while (fscanf(fp, "%i%c", &tmp, &c) >= 1) {
		m= mask;
		for (b= bytesperitem-1; b >= 0; b--) {
			d= (tmp & m) >> (b*8);
			m>>= 8;
			if (x < bi.rowlen && y < height)
				*bp++= swapmap[d];
			x++;
			if (x == bi.rowlen) {
				dbm->SetRow(&bi, y++, bbuf);
				bp= bbuf;
				x= 0;
			}
		}
	}
	delete bbuf;
	return BM;
}

